#include <stdbool.h>
#include <stdio.h>
#include "mtm_ex1.h"

#include "complex.h"

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>

/**
 * These macros are here to help you create tests more easily and keep them
 * clear.
 *
 * The basic idea with unit-testing is create a test function for every real
 * function and inside the test function declare some variables and execute the
 * function under test.
 *
 * Use the ASSERT_MACRO to verify correctness of values.
 */

/**
 * Evaluates b and continues if b is true.
 * If b is false, ends the test by returning false and prints a detailed
 * message about the failure.
 */
#define ASSERT_TRUE(b)                                                         \
do                                                                             \
{                                                                              \
	if( !(b) )                                                                 \
	{                                                                          \
		printf("\nAssertion failed at %s:%d %s\n",__FILE__,__LINE__,#b);  	   \
		return false;                                                          \
	}                                                                          \
} while (0)

/**
 * Macro used for running a test from the main function
 */
#define RUN_TEST(test)                                                         \
do                                                                             \
{                                                                              \
	printf("Running "#test"... ");                                             \
	if( test() )                                                               \
	{                                                                          \
		printf( "[OK]\n" );                                                    \
	}                                                                          \
} while(0)

bool testComplexIsZeroAndCompare()
{
	Complex complex1 = complexCreate( 0, 0 );
	Complex complex2 = complexCreate( 4.4, 6546.8654 );
	Complex complex3 = complexCreate( 4.4, 6546.8654 );

	ASSERT_TRUE( complexIsZero( complex1 ) );
	ASSERT_TRUE( complexIsEqual( complex2, complex3 ) );
	return true;
}

bool testComplexNegate()
{
	Complex complex1 = complexCreate( 123.4589, 1908.1223 );
	Complex complex2 = complexCreate( -123.4589, -1908.1223 );

	ASSERT_TRUE( complexIsEqual( complex2, complexNegate( complex1 ) ) );
	ASSERT_TRUE( complexIsEqual( complex1, complexNegate( complex2 ) ) );
	return true;
}

bool testComplexAdd()
{
	Complex complex1 = complexCreate( 123.4589, -1908.1223 );
	Complex complex2 = complexCreate( 5498.246, 958498354.6546 );
	Complex expected = complexCreate( 5621.7049, 958496446.5323 );

	ASSERT_TRUE( complexIsEqual( complexAdd( complex1, complex2 ), expected ) );
	ASSERT_TRUE( complexIsZero( complexAdd( complex1, complexNegate( complex1 ) ) ));
	return true;
}

bool testComplexSubtract()
{
	Complex complex1 = complexCreate( 123.4589, -1908.1223 );
	Complex complex2 = complexCreate( 5498.246, 958498354.6546 );
	Complex expected = complexCreate( -5374.7871, -958500262.7769 );

	ASSERT_TRUE( complexIsEqual( complexSubtract( complex1, complex2 ), expected ) );
	ASSERT_TRUE( complexIsZero( complexSubtract( complex1, complex1 ) ) );
	return true;
}

bool testComplexMultiply()
{
	Complex complex1 = complexCreate( 123.4589, -1908.1223 );
	Complex complex2 = complexCreate( 5498.246, 9584954.6546 );
	Complex expected = complexCreate( 1.828994452833414698e10,
									  1.17285663240331014e9 );

	ASSERT_TRUE( complexIsEqual( complexMultiply( complex1, complex2 ), expected ) );

	return true;
}

bool testComplexConjugate()
{
	Complex complex = complexCreate( -23.1238, 42.398 );
	Complex expected = complexCreate( -23.1238, -42.398 );

	ASSERT_TRUE( complexIsEqual( complexConjugate( complex ), expected ) );
	ASSERT_TRUE( complexIsEqual( complexConjugate( expected ), complex ) );

	return true;
}

bool testComplexAbsoluteValue()
{
	Complex complex = complexCreate( 12389.12987, 9873.2987 );

	ASSERT_TRUE( isDoubleEqual( complexAbsoluteValue( complex ),
	                            15842.11368962954 ) );

	return true;
}

bool testComplexArgument()
{
	Complex complex = complexCreate( 12389.12987, 9873.2987 );

	ASSERT_TRUE( isDoubleEqual( complexArgument( complex ),
	                            0.67286763856647 ) );

	return true;
}

bool testComplexInverse()
{
	Complex complex = complexCreate( -23.1238, 42.398 );
	Complex expected = complexCreate( -0.00991458849243479829905,
									  -0.018178617826752115927 );

	ASSERT_TRUE(complexIsEqual( complexInverse( complex ), expected ) );
	ASSERT_TRUE(complexIsEqual( complexInverse( expected ), complex ) );
	ASSERT_TRUE(!complexIsValid( complexInverse( complexCreate( 0, 0 ) ) ) );
	ASSERT_TRUE(complexIsEqual(
			complexCreate( 1, 0 ),
			complexMultiply( complex,complexInverse( complex ) ) ) );

	return true;
}

bool testComplexDivide()
{
	Complex complex1 = complexCreate( 123.4589, -1908.1223 );
	Complex complex2 = complexCreate( 5498.246, 9584954.6546 );
	Complex expected = complexCreate( -0.0001990672800038365909,
									  -0.0000129946802425649917295 );

	ASSERT_TRUE( complexIsEqual(
				 complexDivide( complex1, complex2 ),
				 expected ) );
	ASSERT_TRUE( complexIsEqual(
				 complexMultiply( complexDivide( complex1,complex2 ),complex2 ),
				 complex1 ) );
	return true;
}

int main()
{
	RUN_TEST( testComplexIsZeroAndCompare );
	RUN_TEST( testComplexNegate );
	RUN_TEST( testComplexAdd );
	RUN_TEST( testComplexSubtract );
	RUN_TEST( testComplexMultiply );
	RUN_TEST( testComplexInverse );
	RUN_TEST( testComplexConjugate );
	RUN_TEST( testComplexAbsoluteValue );
	RUN_TEST( testComplexArgument );
	RUN_TEST( testComplexDivide );
	return 0;
}
